#include <cpu.h>
#include "../ls7a_config.h"
#include "ht.h"

void ls3a_ht_rx_win(uint64_t base, uint64_t addr, uint64_t size, uint64_t map_addr)
{
	uint32_t val = (((addr >> 24) & 0xffff) << 16) | (~((size - 1) >> 24) & 0xffff);
	readl(base + 4) = val;
	if ((map_addr == 0) && (size <= (1ULL << DMA_NODE_ID_OFFSET)))
		val = 0x80000000;
	else
		val = (0x3UL << 30) | ((map_addr >> 24) & 0x3ffffff);
	readl(base) = val;
}
int ls3a_ht_config(uint64_t base, uint64_t node_id)
{
	pr_info("open 3A ht rx space\n");
	switch (LS3A_NODE_NUM) {
	case 1:
		/*open rx window: 0x0 ~ 0x7f_ffff_ffff*/
		ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN0_OFFSET, 0x0ULL, 0x8000000000, 0ULL);
		break;
	case 2:
	case 4:
		/*related to system chip number, not the 3A - 7A connetion*/
		/*recover node 1 access address (bit 37: node id)*/
		if(node_id) {
			/*Config CPU1-HT1*/
			/*NODE 1*/
			/*open RX window: 0x1000,0000,0000 ~ 0x1040,0000,0000*/
			ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN0_OFFSET, 1ULL << DMA_NODE_ID_OFFSET, 0x4000000000, 1ULL << NODE_OFFSET);
			/*NODE 3*/
			/*open RX window: 0x3000,0000,0000 ~ 0x3020,0000,0000*/
			ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN1_OFFSET, 3ULL << DMA_NODE_ID_OFFSET, 0x2000000000, 3ULL << NODE_OFFSET);
			/*open RX window: 0x3020,0000,0000 ~ 0x3030,0000,0000*/
			ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN2_OFFSET, 3ULL << DMA_NODE_ID_OFFSET, 0x1000000000, 3ULL << NODE_OFFSET);
		} else {
			/*Config CPU0-HT1*/
			/*open Rx window: 0x0 ~ 0x3f_ffff_ffff*/
			ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN0_OFFSET, 0x0ULL, 0x4000000000, 0ULL);
			/*NODE 2*/
			/*open RX window: 0x2000,0000,0000 ~ 0x2040,0000,0000*/
			ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN1_OFFSET, 2ULL << DMA_NODE_ID_OFFSET, 0x4000000000, 2ULL << NODE_OFFSET);
			/*NODE 1,for not 2 way connect*/
			/*open RX window: 0x1000,0000,0000 ~ 0x1040,0000,0000*/
			ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN2_OFFSET, 1ULL << DMA_NODE_ID_OFFSET, 0x4000000000, 1ULL << NODE_OFFSET);
		}
		break;
	case 8:
		/* now default must support 7a 2 way connect */
		if(node_id) {
			/*Config CPU5-HT1*/
			/*NODE 4*/
			/*open RX window: 0x4000,0000,0000 ~ 0x4020,0000,0000*/
			ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN0_OFFSET, 4ULL << DMA_NODE_ID_OFFSET, 0x2000000000, 4ULL << NODE_OFFSET);
			/*NODE 5*/
			/*open RX window: 0x5000,0000,0000 ~ 0x5020,0000,0000*/
			ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN1_OFFSET, 5ULL << DMA_NODE_ID_OFFSET, 0x2000000000, 5ULL << NODE_OFFSET);
			/*NODE 6*/
			/*open RX window: 0x6000,0000,0000 ~ 0x6020,0000,0000*/
			ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN2_OFFSET, 6ULL << DMA_NODE_ID_OFFSET, 0x2000000000, 6ULL << NODE_OFFSET);
			/*NODE 7*/
			/*open RX window: 0x7000,0000,0000 ~ 0x7020,0000,0000*/
			ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN3_OFFSET, 7ULL << DMA_NODE_ID_OFFSET, 0x2000000000, 7ULL << NODE_OFFSET);
		} else {
			/*Config CPU0-HT1*/
			/*open Rx window: 0x0 ~ 0x1f_ffff_ffff*/
			ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN0_OFFSET, 0x0ULL, 0x2000000000, 0ULL);
			if (ls7a_cfg_t.ht.ls7a_2way_connect) {
				/*NODE 1*/
				/*open RX window: 0x1000,0000,0000 ~ 0x1020,0000,0000*/
				ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN1_OFFSET, 1ULL << DMA_NODE_ID_OFFSET, 0x2000000000, 1ULL << NODE_OFFSET);
				/*NODE 2*/
				/*open RX window: 0x2000,0000,0000 ~ 0x2020,0000,0000*/
				ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN2_OFFSET, 2ULL << DMA_NODE_ID_OFFSET, 0x2000000000, 2ULL << NODE_OFFSET);
				/*NODE 3*/
				/*open RX window: 0x3000,0000,0000 ~ 0x3020,0000,0000*/
				ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN3_OFFSET, 3ULL << DMA_NODE_ID_OFFSET, 0x2000000000, 3ULL << NODE_OFFSET);
			} else {
				/*Config CPU0/4-HT1*/
				/*NODE 0 1 2 3 CHIP 0*/
				/*open Rx window: 0x0000,0000,0000 ~ 0x3f_ffff_ffff*/
				ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN1_OFFSET, 0ULL << (DMA_NODE_ID_OFFSET + 2), 0x8000000000, 0ULL << NODE_OFFSET);
				/*node 4 5 6 7 CHIP 1*/
				/*open Rx window: 0x4000,0000,0000 ~ 0x403f_ffff_ffff*/
				ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN2_OFFSET, 1ULL << (DMA_NODE_ID_OFFSET + 2), 0x8000000000, 4ULL << NODE_OFFSET);
			}
		}
		break;
	case 16:
		/*for 7A0*/
		if (node_id >= 10) {
			/*Config CPU10/15-HT1_LO*/
			/*node 8 9 10 11 CHIP 2*/
			/*open Rx window: 0x8000,0000,0000 ~ 0x803f_ffff_ffff*/
			ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN0_OFFSET, 2ULL << (DMA_NODE_ID_OFFSET + 2)/* CHIP (1 << 2) node*/, 0x4000000000, 8ULL << NODE_OFFSET);
			/*node 12 13 14 15 CHIP 3*/
			/*open Rx window: 0xc000,0000,0000 ~ 0xc03f_ffff_ffff*/
			ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN1_OFFSET, 3ULL << (DMA_NODE_ID_OFFSET + 2), 0x4000000000, 0xcULL << NODE_OFFSET);
		} else {
			/*Config CPU0/5-HT1*/
			if (node_id == 0) {
				/*NODE 0 open rx window: 0x0 ~ 0xf_ffff_ffff*/
				ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN0_OFFSET, 0x0ULL, 0x1000000000, 0ULL);
			}
			/*NODE 0 1 2 3 CHIP 0*/
			/*open Rx window: 0x0000,0000,0000 ~ 0x3f_ffff_ffff*/
			ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN1_OFFSET, 0ULL << (DMA_NODE_ID_OFFSET + 2), 0x4000000000, 0ULL << NODE_OFFSET);
			/*node 4 5 6 7 CHIP 1*/
			/*open Rx window: 0x4000,0000,0000 ~ 0x403f_ffff_ffff*/
			ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN2_OFFSET, 1ULL << (DMA_NODE_ID_OFFSET + 2), 0x4000000000, 4ULL << NODE_OFFSET);
			if (!ls7a_cfg_t.ht.ls7a_2way_connect) {
				/*node 8 9 10 11 CHIP 2*/
				/*open Rx window: 0x0000,0000,0000 ~ 0x3f_ffff_ffff*/
				ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN3_OFFSET, 2ULL << (DMA_NODE_ID_OFFSET + 2), 0x4000000000, 8ULL << NODE_OFFSET);
				/*node 12 13 14 15 CHIP 3*/
				/*open Rx window: 0x4000,0000,0000 ~ 0x403f_ffff_ffff*/
				ls3a_ht_rx_win(base + LS3A_HT_RX_CACHE_WIN4_OFFSET, 3ULL << (DMA_NODE_ID_OFFSET + 2), 0x4000000000, 0xcULL << NODE_OFFSET);
			}
		}
		break;
	default:
		pr_info("error: LS3A_NODE_NUM=0x%x\n", LS3A_NODE_NUM);
		break;
	}

	/*set csr_dw_write to 1'b0 to transfer write mask infomation when write data less than 32Byte*/
	pr_info("Disable 3A HT dw_write.\n");
	readl(base + 0x1c0) &= 0xfbffffff;

	pr_info("Set 3A HT int, using 8 bit int.\n");
	readl(base + 0x1c4) |= 0x00000400;

#ifdef ALLOW_EXT_IOI
	pr_info("Set 3A5000 HT EXT int allow, allow kernel to use EXT_IOI.\n");
	readl(base + 0x274) |= 0x40000000;
#else
	pr_info("NOT set 3A5000 HT EXT int allow, forbid kernel to use EXT_IOI.\n");
	readl(PHYS_TO_UNCACHED(0x1fe00000) + 0x8) &= 0xfffffff7;
#endif
#if 0
	int i;
	for (i = 0;i <= 0x20; i += 4)
		pr_info("node%d 0x%x ->0x%lx\n",node_id, i, readl(base + LS3A_HT_RX_CACHE_WIN0_OFFSET + i));
#endif
	return 0;
}

int ls7a_ht_config(uint64_t base)
{

	pr_info("Open 7A HT RX space\n");
	/*window0 00_0000_0000-7f_ffff_ffff*/
	readl(base + LS7A_HT_RX_WIN0_OFFSET + 4) = 0x00008000;
	readl(base + LS7A_HT_RX_WIN0_OFFSET) = 0x80000000;
	pr_info("Open 7A HT RX win0 space\n");

	/*window1 fd_fc00_0000-fd_fcff_ffff*/
	readl(base + LS7A_HT_RX_WIN1_OFFSET + 4) = 0xfdfcffff;
	readl(base + LS7A_HT_RX_WIN1_OFFSET) = 0x80000000;
	pr_info("Open 7A HT RX win1 space\n");

#if 0	/*enable DMA post write*/
	if (LS7A_VERSION) {
		pr_info("Enable 7A HT Post space\n");
		/*window0 00_0000_0000-7f_ffff_ffff*/
		readl(base + LS7A_HT_TX_POST_WIN0_OFFSET + 4) = 0x00008000;
		readl(base + LS7A_HT_TX_POST_WIN0_OFFSET) = 0x80000000;
		readl(base + 0x1c4) &= ~(1 << 11);
	}
#endif
	/*set csr_dw_write to 1'b0 to transfer write mask infomation when write data less than 32Byte*/
	pr_info("Disable 7A HT dw_write.\n");
	readl(base + 0x1c0) &= 0xfbffffff;

	/*enable HT configure access*/
	pr_info("Enable 7A HT configure access\n");
	readl(base + 0x168) = 0xc000fe00;

	return 0;
}
//#define PRINT_HT1_REG
int ls3a7a_ht_config()
{
	uint64_t node_id;
	uint64_t ls3a_ht_base, ls7a_ht_base;
	int i;

	for (i = 0; i < sizeof(ls7a_link_id_buf); i++) {
		node_id = ls7a_link_id_buf[i];
		ls3a_ht_base = (node_id << NODE_OFFSET) | HT1_CTRL_CONF_BASE;
		ls7a_ht_base = (node_id << NODE_OFFSET) | HT1_CONF_BASE;
#ifdef PRINT_HT1_REG
		uint64_t j;
		pr_info("LS3A NODE %d HT registers before init\n", node_id);
		for (j = 0; j < 0x180; j += 0x4) {
			pr_info("0x%llx: 0x%016lx\n", ls3a_ht_base + j, readl(ls3a_ht_base + j));
		}

		pr_info("LS7A to NODE %d HT registers before init\n", node_id);
		for (j = 0; j < 0x268; j += 0x4) {
			pr_info("0x%llx: 0x%016lx\n", ls7a_ht_base + j, readl(ls7a_ht_base + j));
		}
#endif
		/*3A side HT init*/
		ls3a_ht_config(ls3a_ht_base, node_id);
		/*7A side HT configure begin*/
		ls7a_ht_config(ls7a_ht_base);
#ifdef PRINT_HT1_REG
		pr_info("LS3A NODE %d HT registers after init\n", node_id);
		for (j = 0; j < 0x180; j += 0x4) {
			pr_info("0x%llx: 0x%016lx\n", ls3a_ht_base + j, readl(ls3a_ht_base + j));
		}

		pr_info("LS7A to NODE %d HT registers after init\n", node_id);
		for (j = 0; j < 0x268; j += 0x4) {
			pr_info("0x%llx: 0x%016lx\n", ls7a_ht_base + j, readl(ls7a_ht_base + j));
		}
#endif
	}
	return 0;
}
